MyBatis延迟加载和缓存 |
您所在的位置:网站首页 › pb import › MyBatis延迟加载和缓存 |
一、延迟加载
1.主对象的加载:
根本没有延迟的概念,都是直接加载。 2.关联对象的加载时机:01.直接加载: 访问主对象,关联对象也要加载 02.侵入式延迟: 访问主对象,并不加载关联对象 访问主对象属性的属性的时候,关联对象会被加载 03.深度延迟 访问主对象,并不加载关联对象 访问主对象的属性的时候,关联对象也不会被加载 访问关联对象或关联对象的属性的时候,才会加载关联对象。 3.一对多延迟加载代码:01.实体类代码: package cn.pb.bean;import java.util.Set; /** * 国家的实体类 */public class Country { private Integer cId;//国家的编号 private String cName;//国家的名称 //关联省会的属性 private Set provincials; public Integer getcId() { return cId; } public void setcId(Integer cId) { this.cId = cId; } public String getcName() { return cName; } public void setcName(String cName) { this.cName = cName; } public Set getProvincials() { return provincials; } public void setProvincials(Set provincials) { this.provincials = provincials; } } package cn.pb.bean;/** * 省会对应的实体类 */public class Provincial { private Integer pId; //省会的编号 private String pName; //省会名称 public Integer getpId() { return pId; } public void setpId(Integer pId) { this.pId = pId; } public String getpName() { return pName; } public void setpName(String pName) { this.pName = pName; }}
02.dao层代码: public interface CountryDao {/** * 根据国家id 查询国家的信息 以及国家下面的省会 */Country selectCountryById(Integer id);}03.mapper.xml代码: select cid,cname from country where cid=#{xxx} select pid,pname from provincial where countryid=#{xxx}
04.测试代码: public class CountryTest { CountryDao dao=null; SqlSession session=null; Logger log= Logger.getLogger(CountryTest.class);@Before public void before(){ //获取session session= SessionFactoryUtil.getSession(); //获取执行的类对象 dao=session.getMapper(CountryDao.class); } /** * 在所有的test测试方法执行之后 都要执行的操作 */ @After public void after(){ if(session!=null){ session.close(); } } @Test public void testSelectCountryById(){ Country country=dao.selectCountryById(1); log.debug("根据id查询国家信息"+country); } @Test public void testSelectCountryById(){ Country country=dao.selectCountryById(1); log.debug("根据id查询国家信息"+country.getProvincials()); } } 4.配置延迟加载: 在mybatis.xml文件中配置: 二、MyBatis缓存 1.查询缓存的作用: 查询缓存的使用,主要是为了提供查询访问速度。将用户对同一数据的重复查询过程简化,不再每次均从数据库查询获取结果数据,从而提高访问速度。 2.关于缓存的说明:01.MyBatis查询缓存机制。根据缓存区的作用域与生命周期,可划分为两种:一级缓存和二级缓存。 02.MyBatis查询缓存的作用域是根据映射文件的namespace划分的,相同的namespace的mapper查询数据放在同一个缓存区域。不同namespace下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照namespace进行分别存放的。 03.但是一级、二级缓存的不同之处在于,SqlSession一旦关闭,则SqlSession中的数据将不存在,即一级缓存就不复存在。而二级缓存的生命周期与整个应用同步,与SqlSession是否关闭无关。换句话说,一级缓存是在同一线程(同一SqlSession)间共享数据,而二级缓存是在不同线程(不同的SqlSession)间共享数据。 04. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其生命周期为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。 05. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。 06. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。 3.一级缓存: 01.一级缓存存在的证明代码: 001.dao层代码: /** * 根据学生的编号查询对应的信息 * 验证一级缓存的存在 */Student selectStudentById(Integer sId);002.mapper.xml代码: select sid,sname from stu where sid=#{xxx}003.测试代码: package cn.pb;import cn.pb.bean.Student;import cn.pb.dao.StudentDao;import cn.pb.util.SessionFactoryUtil;import org.apache.ibatis.session.SqlSession;import org.apache.log4j.Logger;import org.junit.After;import org.junit.Before;import org.junit.Test; public class StudentTest { StudentDao dao; SqlSession session; Logger logger=Logger.getLogger(StudentDao.class); @Before public void before(){ session= SessionFactoryUtil.getSession(); dao=session.getMapper(StudentDao.class); } /** * 在所有的test测试方法执行之后 都要执行的操作 */ @After public void after(){ if(session!=null){ session.close(); } } /** * 验证一级缓存的存在 * myBatis的一级缓存是一直开启的,并且不能关闭! */ @Test public void test1(){ Student student=dao.selectStudentById(1); logger.debug("第一次查到的id为1的学生:"+student); //再次查询相同的id对象 Student student2 = dao.selectStudentById(1); logger.debug("第2次查到的id为1的学生:"+student2); }} 02.一级缓存--从缓存中查找数据的依据:001.缓存的底层实现是一个Map,Map的value是查询结果 002.Map的key,即查询依据,使用的ORM架构不同,查询依据是不同的 003.MyBatis的查询依据是:Sql的id+SQL语句 004.Hibernate的查询依据是:查询结果对象的id 005.验证代码: a.dao层代码: /** * 验证mybatis缓存查询的依据! */Student selectStudentById2(Integer sId);b.mapper.xml代码: select sid,sname from stu where sid=#{xxx}
c.测试代码: /** * 验证查询的依据 * 两个查询都是查询id为1的学生对象,但是查询语句的id不一致 */@Testpublic void test2() { Student student = dao.selectStudentById(1); logger.debug("第1次查到的id为1的学生:"+student); //再次查询相同的id对象 Student student2 = dao.selectStudentById2(1); logger.debug("第2次查到的id为1的学生:"+student2);} 得到的结论是: mybatis的查询依据是 : mapper文件中sql的id + sql语句! hibernate底层查询的依据是: 查询对象的id!其实缓存的底层是一个map, map的key就是查询依据,value是查询的结果! 03.增、删、改对一级缓存的影响:增删改会清空一级缓存:注意:必须使用insert标签,不能使用select,否则实验做不成功 001.dao层代码: /** * 验证增删改查对一级缓存的影响! */void addStudent(Student student);002.mapper.xml代码: select sid,sname from stu where sid=#{xxx}insert into stu values(#{sId},#{sName}) 003.测试代码: package cn.pb;import cn.pb.bean.Student;import cn.pb.dao.StudentDao;import cn.pb.util.SessionFactoryUtil;import org.apache.ibatis.session.SqlSession;import org.apache.log4j.Logger;import org.junit.After;import org.junit.Before;import org.junit.Test; public class StudentTest { StudentDao dao; SqlSession session; Logger logger=Logger.getLogger(StudentDao.class); @Before public void before(){ session= SessionFactoryUtil.getSession(); dao=session.getMapper(StudentDao.class); } /** * 在所有的test测试方法执行之后 都要执行的操作 */ @After public void after(){ if(session!=null){ session.close(); } } /** * 验证增删改对一级缓存的影响 * 之前是只有一条查询语句! * 但是加上新增语句之后发现出现了再次查询! * * 因为增删改查操作都要清空缓存,把数据同步到数据库, * 保证后续的查询得到正确的结果集! */ @Test public void test3() { Student student = dao.selectStudentById(1); logger.debug("新增之前查询到的stuent:"+student); dao.addStudent(new Student(55, "新增学生")); session.commit(); //再次查询相同的id对象 Student student2 = dao.selectStudentById(1); logger.debug("新增之后查询到的student:"+student2); } } 4.二级缓存: 01.内置二级缓存 001.由于MyBatis从缓存中读取数据的依据与SQL的id相关,而非查询出的对象。所以,使用二级缓存的目的,不是在多个查询间共享查询结果(所有查询中只要查询结果中存在该对象,就直接从缓存中读取,这是对查询结果的共享,Hibernate中的缓存就是为了在多个查询间共享查询结果,但MyBatis不是),而是为了防止同一查询(相同的Sql id,相同的sql语句)的反复执行。 002.MyBatis内置的二级缓存为 https://my.oschina.net/KingPan/blog/280167 http://www.mamicode.com/info-detail-890951.html http://blog.csdn.net/isea533/article/details/44566257 http://blog.csdn.net/u010676959/article/details/43953087 http://blog.csdn.net/xiadi934/article/details/50786293 02.如何开启二级缓存---三条件 001.你cacheEnabled=true,默认值为true 002.你得在Mapper文件中, 003.Entity Implements Serializable 03.增删改对二级缓存的影响 001.增删改也会清空二级缓存 002.对于二级缓存的清空实质上是对value清空为null,key依然存在,并非将Entry删除 003.从DB中进行select查询的条件是: 0001.缓存中根本不存在这个key 0002.存在key对应的Entry,但是value为null 04.二级缓存的配置这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用, 而且返回的对象被认为是只读的 05.可用的收回策略001.LRU – 最近最少使用的:移除最长时间不被使用的对象。 002 FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 003.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。 004.WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。 005.flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 006.形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 007.size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。 008.readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回 缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。 可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。 06.二级缓存的关闭: 001.局部关闭 在mapper文件中修改 增加了useCache="false" 相当于 局部关闭 2级缓存 useCache默认值为true===》把查询放入2级缓存 002.全局关闭 在mybatis.xml文件中增加 07.二级缓存的使用原则: 001. 很少被修改的数据 002. 不是很重要的数据,允许出现偶尔并发的数据 003. 不会被并发访问的数据 004.多个namespace不能操作同一张表 005.不能在关联关系表上执行增删改操作 08.代码验证mybatis2缓存 001. dao层代码: public interface StudentDao { /** * 验证mybatis2级缓存! */ Student selectStudentById(Integer sId); /** * 验证增删改查对2级缓存的影响! */ void addStudent(Student student);} 002. mapper.xml代码: select sid,sname from stu where sid=#{xxx} insert into stu values (#{sId},#{sName})
003. 测试代码: package cn.pb; import cn.pb.bean.Student;import cn.pb.dao.StudentDao;import cn.pb.util.SessionFactoryUtil;import org.apache.ibatis.session.SqlSession;import org.apache.log4j.Logger;import org.junit.After;import org.junit.Before;import org.junit.Test; public class TestStudent { StudentDao dao; SqlSession session; Logger logger=Logger.getLogger(TestStudent.class); @Before public void before(){ session= SessionFactoryUtil.getSession(); dao=session.getMapper(StudentDao.class); } /** * 在所有的test测试方法执行之后 都要执行的操作 */ @After public void after(){ if(session!=null){ session.close(); } } /** * 验证2级缓存 * * 开启内置2级缓存的步骤 * 01.实体类对象 要实现serializable 序列化接口 * 02.在mapper文件中 增加 节点 */ @Test public void test1() { Student student = dao.selectStudentById(1); System.out.println(student); session.close(); //关闭了session 一级缓存中的数据肯定清空了 session = SessionFactoryUtil.getSession(); //再次获取session 查询数据 dao = session.getMapper(StudentDao.class); //这时候不会再有sql语句了 因为2级缓存中存在相同的查询(mapper文件中sql的id)和相同的sql语句 Student student2 = dao.selectStudentById(1); System.out.println(student2); } /** * 验证增删改对2级缓存的影响 */ @Test public void test2() { Student student = dao.selectStudentById(1); System.out.println(student); session.close(); //关闭了session 一级缓存中的数据肯定清空了 session = SessionFactoryUtil.getSession(); //再次获取session 查询数据 dao = session.getMapper(StudentDao.class); //新增学生信息 看看对2级缓存的影响 dao.addStudent(new Student(22,"测试")); Student student2 = dao.selectStudentById(1); System.out.println(student2); } } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |